package com.adouteam.simple.wechat.service;

import com.adouteam.simple.wechat.base.Constant;
import com.adouteam.simple.wechat.base.WechatConstants;
import com.adouteam.simple.wechat.base.WeixinUrls;
import com.adouteam.simple.wechat.bean.ActionInfo;
import com.adouteam.simple.wechat.bean.QrEntity;
import com.adouteam.simple.wechat.bean.QrTypeEnum;
import com.adouteam.simple.wechat.bean.Scene;
import com.adouteam.simple.wechat.tool.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.client.entity.EntityBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.HashMap;

/**
 * 二维码服务
 *
 * @author buxianglong
 */
public class QrService{
    private static final Logger logger = LoggerFactory.getLogger(QrService.class);

    private static final int MAX_COUNT_OF_SCENE_ID_FOR_PERMANENT_QR = 100000;
    private static final Double MAX_COUNT_OF_SCENE_ID_FOR_TEMP_QR = 1E30;
    private static final int MIN_COUNT_OF_SCENE_ID = 0;
    private static final int MAX_LENGTH_OF_SCENE_STR = 64;

    private static final String FLAG_OF_TICKET = "ticket";

    public static String getTempQrUrl(int sceneId, Integer expireSeconds, WechatConstants wechatConstants){
        String ticketForTempQr = getTicketForTempQr(sceneId, expireSeconds, wechatConstants);
        return buildQrUrlBasedOnTicket(ticketForTempQr, wechatConstants);
    }

    public static String getTempQrUrl(String sceneStr, Integer expireSeconds, WechatConstants wechatConstants){
        String ticketForTempQr = getTicketForTempQr(sceneStr, expireSeconds, wechatConstants);
        return buildQrUrlBasedOnTicket(ticketForTempQr, wechatConstants);
    }

    public static String getPermanentQrUrl(int sceneId, WechatConstants wechatConstants){
        String ticketForPermanentQr = getTicketForPermanentQr(sceneId, wechatConstants);
        return buildQrUrlBasedOnTicket(ticketForPermanentQr, wechatConstants);
    }

    public static String getPermanentQrUrl(String sceneStr, WechatConstants wechatConstants){
        String ticketForPermanentQr = getTicketForPermanentQr(sceneStr, wechatConstants);
        return buildQrUrlBasedOnTicket(ticketForPermanentQr, wechatConstants);
    }

    /**
     * 拿Ticket凭据，构建二维码地址
     *
     * @param ticket          Ticket凭据
     * @param wechatConstants 微信配置
     * @return
     */
    private static String buildQrUrlBasedOnTicket(String ticket, WechatConstants wechatConstants){
        return WeixinUrls.replace(WeixinUrls.QR_IMAGE_URL, wechatConstants, new HashMap<String, String>(1){
            private static final long serialVersionUID = -7881219608435342338L;

            {
                try{
                    put("TICKET", URLEncoder.encode(ticket, "utf-8"));
                }catch(UnsupportedEncodingException e){
                    logger.error(Constant.LOGGER_PREFIX + "Failed to encode parameter", e);
                }
            }
        });
    }

    /**
     * 获取永久二维码的Ticket
     *
     * @param sceneId         场景id
     * @param wechatConstants 微信配置
     * @return
     */
    private static String getTicketForPermanentQr(int sceneId, WechatConstants wechatConstants){
        if(sceneId > MAX_COUNT_OF_SCENE_ID_FOR_PERMANENT_QR || sceneId <= MIN_COUNT_OF_SCENE_ID){
            return "";
        }
        return requestForTicket(sceneId, QrTypeEnum.QR_PERMANET_INT, null, wechatConstants);
    }

    /**
     * 获取永久二维码的Ticket
     *
     * @param sceneStr        场景id
     * @param wechatConstants 微信配置
     * @return
     */
    private static String getTicketForPermanentQr(String sceneStr, WechatConstants wechatConstants){
        if(StringUtils.isBlank(sceneStr) || StringUtils.length(sceneStr) > MAX_LENGTH_OF_SCENE_STR){
            return "";
        }
        return requestForTicket(sceneStr, QrTypeEnum.QR_PERMANET_STR, null, wechatConstants);
    }

    /**
     * 获取临时二维码的Ticket
     *
     * @param sceneId         场景id
     * @param expireSeconds   二维码有效期/Ticket凭据有效期，单位：秒
     * @param wechatConstants 微信配置
     * @return
     */
    private static String getTicketForTempQr(int sceneId, Integer expireSeconds, WechatConstants wechatConstants){
        if(sceneId > MAX_COUNT_OF_SCENE_ID_FOR_TEMP_QR || sceneId <= MIN_COUNT_OF_SCENE_ID){
            return "";
        }
        return requestForTicket(sceneId, QrTypeEnum.QR_TEMP_INT, expireSeconds, wechatConstants);
    }

    /**
     * 获取临时二维码的Ticket
     *
     * @param sceneStr        场景id
     * @param expireSeconds   二维码有效期/Ticket凭据有效期，单位：秒
     * @param wechatConstants 微信配置
     * @return
     */
    private static String getTicketForTempQr(String sceneStr, Integer expireSeconds, WechatConstants wechatConstants){
        if(StringUtils.isBlank(sceneStr) || StringUtils.length(sceneStr) > MAX_LENGTH_OF_SCENE_STR){
            return "";
        }
        return requestForTicket(sceneStr, QrTypeEnum.QR_TEMP_STR, expireSeconds, wechatConstants);
    }

    /**
     * 获取指定类型二维码的Ticket
     *
     * @param sceneId         场景值ID
     * @param qrTypeEnum      二维码类型枚举
     * @param expireSeconds   二维码有效期/Ticket凭据有效期，单位：秒
     * @param wechatConstants 微信配置
     * @return
     */
    private static String requestForTicket(Object sceneId, QrTypeEnum qrTypeEnum, Integer expireSeconds, WechatConstants wechatConstants){
        String url = WeixinUrls.replace(WeixinUrls.QR_TICKET_URL, wechatConstants, null);
        String jsonPost = createJson(sceneId, qrTypeEnum, expireSeconds);
        HttpEntity httpEntity = EntityBuilder.create()
                .setText(jsonPost).setContentType(ContentType.APPLICATION_JSON)
                .setContentEncoding(Consts.UTF_8.name())
                .build();
        return HttpUtil.post(url, null, httpEntity, (httpResponse -> {
            String responseContent = EntityUtils.toString(httpResponse.getEntity(), Charset.forName("utf-8"));
            JSONObject json = JSONObject.parseObject(responseContent);
            if(json.containsKey(FLAG_OF_TICKET)){
                return json.getString(FLAG_OF_TICKET);
            }else{
                return "";
            }
        }));
    }

    /**
     * 创建请求参数json数据
     *
     * @param sceneId       场景id
     * @param qrTypeEnum    二维码类型枚举
     * @param expireSeconds 二维码有效期/Ticket凭据有效期，单位：秒
     * @return
     */
    private static String createJson(Object sceneId, QrTypeEnum qrTypeEnum, Integer expireSeconds){
        Scene scene = new Scene();
        switch(qrTypeEnum){
            case QR_TEMP_INT:
                scene.setScene_id((int) sceneId);
                break;
            case QR_TEMP_STR:
                scene.setScene_str((String) sceneId);
                break;
            case QR_PERMANET_INT:
                scene.setScene_id((int) sceneId);
                break;
            case QR_PERMANET_STR:
                scene.setScene_str((String) sceneId);
                break;
            default:
        }
        ActionInfo actionInfo = new ActionInfo(scene);
        QrEntity qrEntity = new QrEntity(expireSeconds, qrTypeEnum.getActionName(), actionInfo);
        String requestJsonBody = JSON.toJSONString(qrEntity);
        logger.debug(Constant.LOGGER_PREFIX + "Ticket request json body:" + requestJsonBody);
        return requestJsonBody;
    }
}
